//
//  GaiaGattCommand.swift
//  Nexs
//
//  Created by roni on 2025/7/29.
//

import Foundation

/// GaiaGattCommand 封装包含帧和数据的数据包
public class GaiaGattCommand {
    
    // MARK: - 属性
    
    /// 命令的原始数据
    public var command: Data
    
    /// 命令类型
    public var commandId: GaiaCommandType? {
        get {
            if let id = _commandId {
                return GaiaCommandType(rawValue: id & GaiaConstants.commandMask)
            }
            return nil
        }
        set {
            _commandId = newValue?.rawValue
            updateCommandIdInBuffer()
        }
    }
    
    /// 厂商ID
    public var vendorId: UInt16 {
        get {
            return _vendorId
        }
        set {
            _vendorId = newValue
            updateVendorIdInBuffer()
        }
    }
    
    // MARK: - 私有属性
    
    private var _commandId: UInt16? = 0
    private var _vendorId: UInt16 = 0
    
    // MARK: - 初始化方法
    
    /// 使用数据创建命令
    /// - Parameter data: 命令数据
    public init(data: Data? = nil) {
        if let data = data, data.count >= GaiaConstants.gattHeaderSize {
            self.command = data
            parseHeader()
        } else {
            self.command = Data()
        }
    }
    
    /// 使用长度创建命令（数据需要单独设置）
    /// - Parameter length: 完整命令包的长度
    public init?(length: Int) {
        guard length >= GaiaConstants.gattHeaderSize else {
            return nil
        }
        
        self.command = Data(count: length)
    }
    
    /// 使用命令类型和厂商ID创建命令
    /// - Parameters:
    ///   - commandType: 命令类型
    ///   - vendor: 厂商ID
    public init(commandType: GaiaCommandType, vendor: UInt16) {
        self.command = Data()
        self._commandId = commandType.rawValue
        self._vendorId = vendor
        
        // 构建基本的头部
        var vendorBytes = vendor.bigEndian
        var commandBytes = commandType.rawValue.bigEndian
        
        command.append(Data(bytes: &vendorBytes, count: MemoryLayout<UInt16>.size))
        command.append(Data(bytes: &commandBytes, count: MemoryLayout<UInt16>.size))
    }
    
    // MARK: - 公共方法
    
    /// 获取数据包长度
    /// - Returns: 数据包长度
    public func length() -> Int {
        return command.count
    }
    
    /// 获取数据包
    /// - Returns: 数据包的副本
    public func getPacket() -> Data {
        return command
    }
    
    /// 获取载荷长度
    /// - Returns: 载荷长度
    public func getPayloadLength() -> Int {
        return command.count - GaiaConstants.gattHeaderSize
    }
    
    /// 设置命令ID
    /// - Parameter type: 命令类型
    public func setCommandId(_ type: GaiaCommandType) {
        commandId = type
    }
    
    /// 获取命令ID（移除潜在的ACK位）
    /// - Returns: 命令类型
    public func getCommandId() -> GaiaCommandType? {
        if let id = _commandId {
            return GaiaCommandType(rawValue: id & GaiaConstants.commandMask)
        }
        
        return nil
    }
    
    /// 设置厂商ID
    /// - Parameter vendorId: 厂商ID
    public func setVendorId(_ vendorId: UInt16) {
        self.vendorId = vendorId
    }
    
    /// 获取厂商ID
    /// - Returns: 厂商ID
    public func getVendorId() -> UInt16 {
        return vendorId
    }
    
    /// 添加载荷到Gaia命令
    /// - Parameter payload: 要与命令一起发送的数据
    public func addPayload(_ payload: Data) {
        command.append(payload)
    }
    
    /// 返回包含GaiaCommand载荷副本的NSData对象
    /// - Returns: 载荷数据
    public func getPayload() -> Data? {
        let payloadLength = getPayloadLength()
        
        guard payloadLength > 0, command.count >= GaiaConstants.headerOffsetPayload + payloadLength else {
            return nil
        }
        
        let range = GaiaConstants.headerOffsetPayload..<(GaiaConstants.headerOffsetPayload + payloadLength)
        return command.subdata(in: range)
    }
    
    /// 确定GaiaCommand是否为确认
    /// - Returns: 如果命令是确认则返回true
    public func isAcknowledgement() -> Bool {
        if let id = _commandId {
            return (id & GaiaConstants.commandAckMask) != 0
        }
        
        return false
    }
    
    /// 读取命令状态
    /// - Returns: 命令状态
    public func status() -> GaiaCommandStatus {
        guard getPayloadLength() >= 1, command.count > GaiaConstants.headerOffsetPayload else {
            return .noStatusAvailable
        }
        
        let statusByte = command[GaiaConstants.headerOffsetPayload]
        return GaiaCommandStatus(rawValue: statusByte) ?? .noStatusAvailable
    }
    
    /// 设置是否为GATT命令
    /// - Parameter isShortPacket: 是否为短包
    public func setIsGattCommand(_ isShortPacket: Bool) {
        guard command.count >= 2 else { return }
        
        command[GaiaConstants.headerOffsetVendorId] = isShortPacket ? 0x55 : 0x56
        command[GaiaConstants.headerOffsetVendorId + 1] = UInt8(command.count & 0xFF)
    }
    
    // MARK: - 私有方法
    
    /// 解析头部信息
    private func parseHeader() {
        guard command.count >= GaiaConstants.gattHeaderSize else { return }
        
        // 解析厂商ID
        let vendorBytes = command.subdata(in: GaiaConstants.headerOffsetVendorId..<GaiaConstants.headerOffsetVendorId + 2)
        _vendorId = vendorBytes.withUnsafeBytes { $0.load(as: UInt16.self) }.bigEndian
        
        // 解析命令ID
        let commandBytes = command.subdata(in: GaiaConstants.headerOffsetCommandId..<GaiaConstants.headerOffsetCommandId + 2)
        _commandId = commandBytes.withUnsafeBytes { $0.load(as: UInt16.self) }.bigEndian
    }
    
    /// 更新缓冲区中的命令ID
    private func updateCommandIdInBuffer() {
        guard command.count >= GaiaConstants.headerOffsetCommandId + 2 else { return }
        
        guard let id = _commandId else {
            return
        }
        
        var commandBytes = id.bigEndian
        let data = Data(bytes: &commandBytes, count: MemoryLayout<UInt16>.size)
        
        command.replaceSubrange(GaiaConstants.headerOffsetCommandId..<GaiaConstants.headerOffsetCommandId + 2, with: data)
    }
    
    /// 更新缓冲区中的厂商ID
    private func updateVendorIdInBuffer() {
        guard command.count >= GaiaConstants.headerOffsetVendorId + 2 else { return }
        
        var vendorBytes = _vendorId.bigEndian
        let data = Data(bytes: &vendorBytes, count: MemoryLayout<UInt16>.size)
        
        command.replaceSubrange(GaiaConstants.headerOffsetVendorId..<GaiaConstants.headerOffsetVendorId + 2, with: data)
    }
}

// MARK: - 扩展：便利方法
public extension GaiaGattCommand {
    
    /// 创建一个简单的命令
    /// - Parameters:
    ///   - commandType: 命令类型
    ///   - vendor: 厂商ID
    ///   - payload: 载荷数据
    /// - Returns: 新的GaiaGattCommand实例
    static func createCommand(commandType: GaiaCommandType, vendor: UInt16, payload: Data? = nil) -> GaiaGattCommand {
        let command = GaiaGattCommand(commandType: commandType, vendor: vendor)
        if let payload = payload {
            command.addPayload(payload)
        }
        return command
    }
    
    /// 检查命令是否有效
    /// - Returns: 如果命令有效则返回true
    func isValid() -> Bool {
        return command.count >= GaiaConstants.gattHeaderSize
    }
    
    /// 获取十六进制字符串表示
    /// - Returns: 命令的十六进制字符串
    func hexString() -> String {
        return command.map { String(format: "%02X", $0) }.joined(separator: " ")
    }
}

// MARK: - CustomStringConvertible
extension GaiaGattCommand: CustomStringConvertible {
    public var description: String {
        let cmd = getCommandId()
        let vendor = getVendorId()
        let payloadLength = getPayloadLength()
        let isAck = isAcknowledgement()
        
        return "GaiaGattCommand(cmd: \(String(describing: cmd)), vendor: 0x\(String(vendor, radix: 16, uppercase: true)), payload: \(payloadLength) bytes, ack: \(isAck))"
    }
} 
